package net.fdukedom.epicurus.domain.util;

import java.util.List;

import net.fdukedom.epicurus.domain.entity.Activation;
import net.fdukedom.epicurus.domain.entity.User;
import net.fdukedom.epicurus.tools.logging.Logger;
import net.fdukedom.epicurus.tools.logging.WriterId;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.LogicalExpression;

/**
 * Utility class for Users' routine.
 *
 * @author Dmitry Y. Kochelaev
 */
public final class UserHelper {

    /**
     * The only instance of the class.
     */
    private static final UserHelper instance = new UserHelper();

    private Logger logger = Logger.getInstance(WriterId.DOMAIN);

    /**
     * Default constructor.
     */
    private UserHelper() {
        //this is an utility class only one instance is allowed
    }

    /**
     * Returns the only instance of the class.
     *
     * @return the only instance of the class
     */
    public static UserHelper getInstance() {
        return instance;
    }

    /**
     * Saves user record in database.
     *
     * @param user user to save
     */
    public synchronized void saveUser(User user) {
        Session session = HibernateUtil.getSession();
        session.saveOrUpdate(user);
        logger.logDebug("User was saved: " + user);
    }
    
    /**
     * Saves user activation code.
     *
     * @param user user instance
     */
    public synchronized String saveActivation(User user) {
        String code = user.getName(); 
        code += Long.toString((long) (Math.random() * Long.MAX_VALUE));
        code += Long.toString((long) (Math.random() * Long.MAX_VALUE));
        Activation activation = new Activation(user, code);
        Session session = HibernateUtil.getSession();
        session.saveOrUpdate(activation);
        Logger.getInstance(WriterId.DOMAIN).logInfo("User activation was saved: " + activation);
        return code;
    }

    /**
     * Loads user by id.
     *
     * @param id user id
     * @return user with specified id or null if no user was found
     */
    public User load(int id) {
        Session session = HibernateUtil.getSession();
        Criteria criteria = session.createCriteria(User.class);
        List users = criteria.add(Expression.eq("id", id)).list();
        if (users.size() > 0) {
            return (User) users.get(0);
        }
        Logger.getInstance(WriterId.DOMAIN).logInfo("Failed user lookup. User id " + id);
        return null;
    }

    /**
     * Finds user in database by e-mail or name.
     *
     * @param email user e-mail
     * @param name user name
     * @return if user with such name OR e-mail was found
     */
    public boolean findByEmailOrName(String email, String name) {
        Session session = HibernateUtil.getSession();
        Criteria criteria = session.createCriteria(User.class);
        LogicalExpression expression = Expression.or(Expression.like("email", email),
                                                     Expression.like("name", name));

        List users = criteria.add(expression).list();
        return (users.size() > 0);
    }

    /**
     * Finds user in database by e-mail.
     *
     * @param email user e-mail
     * @return user with corresponding email or null if no user was found
     */
    public User findByEmail(String email) {
        Session session = HibernateUtil.getSession();
        Criteria criteria = session.createCriteria(User.class);
        List users = criteria.add(Expression.like("email", email)).list();
        if (users.size() > 0) {
            return (User) users.get(0);
        }
        Logger.getInstance(WriterId.DOMAIN).logInfo("Failed user lookup. User email " + email);
        return null;
    }

    /**
     * Finds user in database by name.
     *
     * @param name user's name
     *
     * @return user with corresponding name or null if no user was found
     */
    public User findByName(String name) {
        Session session = HibernateUtil.getSession();
        Criteria criteria = session.createCriteria(User.class);
        List users = criteria.add(Expression.like("name", name)).list();
        if (users.size() > 0) {
            return (User) users.get(0);
        }
        logger.logInfo("Failed user lookup. User name " + name);
        return null;
    }

    /**
     * Finds user in database by activation code.
     *
     * @param code user's activation code
     *
     * @return user with corresponding activation code or null if no user was found
     */
    public User findByActivationCode(String code) {
        Session session = HibernateUtil.getSession();
        Criteria criteria = session.createCriteria(Activation.class);
        List found = criteria.add(Expression.like("code", code)).list();
        if (found.size() > 0) {
            return ((Activation) found.get(0)).getUser();
        }
        logger.logInfo("Failed user lookup. Activation code " + code);
        return null;
    }
}

